/**
 * @file main.cpp
 * @brief 角点网格界面提取程序的主入口
 * 
 * 程序功能:
 * 1. 读取角点网格数据(baseGrid.out)
 * 2. 读取断层数据(faults.txt)
 * 3. 提取地层界面和断层界面
 * 4. 输出VTK格式的界面文件
 */

#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#endif

#include "GridModel.h"
#include "SurfaceExtractor.h"
#include "VTKWriter.h"
#include "GridGenerator.h"
#include "ImplicitBuilder.h"
#include "MeshCutter.h"
#include "MeshExtender.h"
#include "PropertyMapper.h"
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <chrono>
#include <iomanip>  // 添加对std::setprecision的支持
#include <numeric>  // 添加对std::iota的支持
#include <random>   // 添加对随机数的支持
#include <variant>

/**
 * @brief 将UTF-8字符串转换为宽字符串
 */
std::wstring utf8ToWide(const std::string& str) {
#ifdef _WIN32
    if (str.empty()) return std::wstring();
    
    // 获取所需的缓冲区大小
    int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
    if (size <= 0) return std::wstring();

    // 分配缓冲区并进行转换
    std::vector<wchar_t> buffer(size);
    if (MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, buffer.data(), size) <= 0) {
        return std::wstring();
    }

    return std::wstring(buffer.data());
#else
    return std::wstring(str.begin(), str.end());
#endif
}

/**
 * @brief 设置控制台UTF-8编码
 */
void setUTF8Console() {
#ifdef _WIN32
    // 设置控制台代码页为UTF-8
    SetConsoleOutputCP(CP_UTF8);
    SetConsoleCP(CP_UTF8);
    
    // 启用控制台的UTF-8支持
    _setmode(_fileno(stdout), _O_U8TEXT);
    _setmode(_fileno(stdin), _O_U8TEXT);
    _setmode(_fileno(stderr), _O_U8TEXT);
#endif
}

/**
 * @brief 程序入口函数
 * @return 成功返回0,失败返回1
 * 
 * 主要执行流程:
 * 1. 设置输入输出文件路径
 * 2. 加载角点网格数据
 * 3. 提取界面并生成三角形网格
 * 4. 输出VTK格式结果
 * 5. 异常处理和错误报告
 */
int main(int argc, char* argv[]) {
    try {
        // 设置UTF-8编码
        setUTF8Console();

        // 设置输入输出文件路径
        std::string input_grid = "./final/input/baseGrid.out";
        std::string input_fault = "./final/input/faults.txt";
        std::string output_file = "./final/output/finiteGrid.vtk";

        // 检查文件是否存在
        std::ifstream check_grid(input_grid);
        if (!check_grid) {
            std::wcerr << L"错误: 无法找到网格文件: " << utf8ToWide(input_grid) << std::endl;
            return 1;
        }
        check_grid.close();

        std::ifstream check_fault(input_fault);
        if (!check_fault) {
            std::wcerr << L"错误: 无法找到断层文件: " << utf8ToWide(input_fault) << std::endl;
            return 1;
        }
        check_fault.close();

        // 读取角点网格数据
        GridModel gridModel;
        gridModel.loadFromFile(input_grid);

        // 创建界面提取器
        SurfaceExtractor extractor(gridModel);
        extractor.loadFaultData(input_fault);
        extractor.extractSurfaces();
        
        // 输出提取的界面到VTK文件
        VTKWriter::writeVTKFile("./final/output/surfaces.vtk", extractor);

        // 生成初始网格
        double gridSize = 100.0;  // 基础网格尺寸
        GridGenerator generator(extractor, gridSize);
        
        if (!generator.generateInitialGrid()) {
            std::wcerr << L"错误: 初始网格生成失败" << std::endl;
            return 1;
        }
        
        // 构建隐式函数
        ImplicitBuilder implicitBuilder(gridSize);
        
        // 构建地层界面
        std::vector<std::shared_ptr<ImplicitSurface>> strataSurfaces;
        std::map<int, std::vector<Point3D>> strataPoints;
        for (const auto& vertex : extractor.getVertices()) {
            if (vertex.type >= 11) {  // 地层界面点
                strataPoints[vertex.type].push_back(vertex);
            }
        }
        
        for (const auto& [layer_type, points] : strataPoints) {
            auto surface = implicitBuilder.buildStrataSurface(points);
            if (surface) {
                strataSurfaces.push_back(surface);
            }
        }
        
        // 修改faultSurfaces的声明
        std::vector<ImplicitBuilder::FaultSurfaceResult> faultSurfaces;
        faultSurfaces.reserve(extractor.getFaultData().size());

        // 构建断层界面
        for (const auto& faultData : extractor.getFaultData()) {
            auto surface = implicitBuilder.buildFaultSurface(faultData.nodes);
            faultSurfaces.push_back(std::move(surface));
        }
        
        std::wcout << L"构建完成 - " << strataSurfaces.size() << L"个地层界面, " 
                   << faultSurfaces.size() << L"个断层界面" << std::endl;
        
        // 找到最后一个地层界面的类型
        int lastStrataType = 11;  // 初始值设为第一个地层界面类型
        for (const auto& node : extractor.getVertices()) {
            if (node.type >= 11) {  // 地层界面点
                lastStrataType = std::max(lastStrataType, node.type);
            }
        }

        // 创建网格切割器
        MeshCutter mesh_cutter(generator.getNodes(), generator.getElements(), gridSize, lastStrataType);
        
        // 处理地层界面（从上到下，编号11-20）
        for (size_t i = 0; i < strataSurfaces.size(); ++i) {
            int surface_type = 11 + i;  // 从11开始递增
            std::wcout << L"处理地层界面 " << surface_type << std::endl;
            mesh_cutter.processSurface(*strataSurfaces[i], surface_type);
        }
        
        // 处理断层界面（编号1-10）
        for (size_t i = 0; i < faultSurfaces.size(); ++i) {
            int surface_type = i + 1;  // 从1开始递增
            std::wcout << L"处理断层界面 " << surface_type << std::endl;
            
            std::visit([&](const auto& surface) {
                using T = std::decay_t<decltype(surface)>;
                if constexpr (std::is_same_v<T, std::vector<std::shared_ptr<ImplicitSurface>>>) {
                    std::wcout << L"断层分为" << surface.size() << L"段处理" << std::endl;
                    mesh_cutter.processSurface(surface, surface_type);
                } else if constexpr (std::is_same_v<T, std::shared_ptr<ImplicitSurface>>) {
                    mesh_cutter.processSurface(*surface, surface_type);
                }
            }, faultSurfaces[i]);
        }
        
        // 在网格切割完成后
        ExtendParams extendParams;  // 使用默认参数或从配置文件读取

        // 在网格延拓之前，获取GridGenerator计算的网格尺寸
        double x_length = generator.getXMax() - generator.getXMin();
        double y_length = generator.getYMax() - generator.getYMin();
        double z_length = generator.getZMax() - generator.getZMin();

        int nx = static_cast<int>(std::floor(x_length / gridSize));
        int ny = static_cast<int>(std::floor(y_length / gridSize));
        int nz = static_cast<int>(std::floor(z_length / gridSize));

        nx = std::max(1, nx);
        ny = std::max(1, ny);
        nz = std::max(1, nz);

        double actual_dx = x_length / nx;
        double actual_dy = y_length / ny;
        double actual_dz = z_length / nz;

        // 创建GridSizes结构体
        GridSizes gridSizes{
            generator.getActualDX(),
            generator.getActualDY(),
            generator.getActualDZ()
        };

        // 执行网格延拓时传入网格尺寸
        MeshExtender extender(
            const_cast<std::vector<Point3D>&>(mesh_cutter.getNodes()),
            const_cast<std::vector<Tetrahedron>&>(mesh_cutter.getElements()),
            extendParams,
            gridSizes  // 传入网格尺寸
        );
        extender.extend();

        // 在网格延拓完成后
        PropertyMapper propertyMapper;
        propertyMapper.setKNearestPoints(20);  // 使用20个最近邻点

        std::vector<CellProperty> mappedProps;
        propertyMapper.process("./final/input/fineGrid.out", 
                              "./final/input/Props.txt",
                              extender.getNodes(),
                              extender.getElements(),
                              mappedProps);

        // 输出最终网格到VTK文件
        std::ofstream outFile(output_file);
        if (!outFile) {
            std::wcerr << L"错误: 无法创建输出文件" << std::endl;
            return 1;
        }

        // 写入VTK文件头
        outFile << "# vtk DataFile Version 3.0\n";
        outFile << "Extended Grid with Surrounding Rocks\n";
        outFile << "ASCII\n";
        outFile << "DATASET UNSTRUCTURED_GRID\n\n";

        // 获取延拓后的节点和单元
        const auto& nodes = extender.getNodes();        // 使用extender的节点
        const auto& elements = extender.getElements();   // 使用extender的单元

        // 写入所有节点（包括延拓部分）
        outFile << "POINTS " << nodes.size() << " double\n";
        for (const auto& node : nodes) {
            outFile << std::fixed << std::setprecision(6)
                   << node.x << " " << node.y << " " << node.z << "\n";
        }
        outFile << "\n";

        // 写入所有单元（包括延拓部分）
        outFile << "CELLS " << elements.size() << " " << elements.size() * 5 << "\n";
        for (const auto& tet : elements) {
            outFile << "4 " << tet.v1 << " " << tet.v2 << " "
                   << tet.v3 << " " << tet.v4 << "\n";
        }
        outFile << "\n";

        // 写入单元类型
        outFile << "CELL_TYPES " << elements.size() << "\n";
        for (size_t i = 0; i < elements.size(); ++i) {
            outFile << "10\n";  // VTK_TETRA = 10
        }
        outFile << "\n";

        // 写入节点数据
        outFile << "POINT_DATA " << nodes.size() << "\n";
        outFile << "SCALARS IsInterface int 1\n";
        outFile << "LOOKUP_TABLE default\n";
        for (const auto& node : nodes) {
            outFile << node.type << "\n";
        }

        // 写入单元区域标记
        outFile << "\nCELL_DATA " << elements.size() << "\n";
        outFile << "SCALARS CellZone int 1\n";
        outFile << "LOOKUP_TABLE default\n";
        const auto& cellZones = extender.getCellZones();
        for (int zone : cellZones) {
            outFile << zone << "\n";
        }

        // 输出属性数据（只在开始写一次CELL_DATA）
        //outFile << "\nCELL_DATA " << mappedProps.size() << "\n";

        // 输出杨氏模量
        outFile << "SCALARS YoungModulos float\n";
        outFile << "LOOKUP_TABLE default\n";
        for (const auto& prop : mappedProps) {
            outFile << std::fixed << std::setprecision(6) << prop.youngModulos << "\n";
        }

        // 输出泊松比（不再重复写CELL_DATA）
        outFile << "SCALARS PoissonRatio float\n";
        outFile << "LOOKUP_TABLE default\n";
        for (const auto& prop : mappedProps) {
            outFile << std::fixed << std::setprecision(6) << prop.poissonRatio << "\n";
        }

        // 输出岩石密度（不再重复写CELL_DATA）
        outFile << "SCALARS RockDensity float\n";
        outFile << "LOOKUP_TABLE default\n";
        for (const auto& prop : mappedProps) {
            outFile << std::fixed << std::setprecision(6) << prop.rockDensity << "\n";
        }

        // 输出孔隙度（不再重复写CELL_DATA）
        outFile << "SCALARS Porosity float\n";
        outFile << "LOOKUP_TABLE default\n";
        for (const auto& prop : mappedProps) {
            outFile << std::fixed << std::setprecision(6) << prop.porosity << "\n";
        }

        outFile.close();
        std::wcout << L"处理完成，已生成 " << utf8ToWide(output_file) << std::endl;
        
        return 0;
    }
    catch (const std::exception& e) {
        std::wcerr << L"错误: " << utf8ToWide(e.what()) << std::endl;
        return 1;
    }
} 